
//#include "../net/Broker4.h"
#include "../iface/APRInterface.h"
//#include "BaseConvert.h"
#include "StringUtils.h"
#include "RunningWorkProcess.h"
#include <apr_strings.h>

/** Constructor for the work process. Also starts the process. Should
 * be noted that this waits for a while to enure the process begins
 * first.
 * 
 * @param directorypath The directory that the process starts in.
 * 
 * @param instancenumber The local instance number that is to be
 * supplied to the process.
 * 
 * @param totalinstances The total instances of which this instance is
 * a member.
 * 
 * @param imp The memory pool to be used to parent the memory pool to
 * use in this class. */
RunningWorkProcess::RunningWorkProcess(const char *directorypath, int instancenumber, int totalinstances, apr_pool_t *imp)
{
   finished = 0;
   apr_status_t status;
   status = apr_pool_create(&mp, imp);
   CheckAPRError(status);
   
   char *runcommand = apr_pstrcat(mp, directorypath, "/", "go.sh", NULL);
   char *str_instance = StringUtils::mpprintf(mp, "%d", instancenumber);
   char *str_totalinstance = StringUtils::mpprintf(mp, "%d", totalinstances);

   const char *all_argv[4];
   all_argv[0] = "/bin/sh";
   all_argv[1] = runcommand;
   all_argv[2] = str_instance;
   all_argv[3] = str_totalinstance;
   all_argv[4] = NULL;

   directory_name = apr_pstrdup(mp, directorypath);
   
   status = apr_procattr_create(&pattr, mp);
   CheckAPRError(status);
   status = apr_procattr_io_set(pattr, APR_NO_PIPE, APR_NO_PIPE, APR_NO_PIPE);
   CheckAPRError(status);
   status = apr_procattr_cmdtype_set(pattr, APR_PROGRAM_ENV);
   CheckAPRError(status);
   status = apr_procattr_dir_set(pattr, directorypath);
   CheckAPRError(status);
   status = apr_proc_create(&tproc, all_argv[0], (const char* const*)all_argv, NULL, pattr, mp);
   CheckAPRError(status);

   apr_sleep(1000000);
   int result;
   apr_exit_why_e why;
   status = apr_proc_wait(&tproc, &result, &why, APR_NOWAIT);
   if ((APR_STATUS_IS_CHILD_DONE(status)) && (why != APR_PROC_EXIT))
   {
      errprint("problem starting child process '%s' (%d, %d)", runcommand, why, result);
   }
   if ((APR_STATUS_IS_CHILD_DONE(status)) && (why == APR_PROC_EXIT) && (result != 0))
   {
      errprint("problem starting child process '%s' - result code non-zero (%d)", runcommand, result);
   }
   if (APR_STATUS_IS_CHILD_DONE(status)) finished = 1;
}

/** Destructor for the work process. Kills the process if it has not
 * finished yet before freeing everything. */
RunningWorkProcess::~RunningWorkProcess()
{
   apr_status_t status;
   int result;
   apr_exit_why_e why;
   if ((directory_name) && (!finished))
   {
      status = apr_proc_wait(&tproc, &result, &why, APR_NOWAIT);
      if (APR_STATUS_IS_CHILD_NOTDONE(status))
      {
         errprint("work still running at destructor time");
#ifndef WAITFORPROC
         status = apr_proc_kill(&tproc, SIGTERM);
         CheckAPRError(status);
#endif
         status = apr_proc_wait(&tproc, &result, &why, APR_WAIT);
         if (APR_STATUS_IS_CHILD_NOTDONE(status))
            errprint("child process is still running");
      }
      if (result != 0)
         errprint("exit code from '%s' non-zero (%d)", "go.sh", result);
   }
   apr_pool_destroy(mp);
}

/** Determine whether the process has exited yet.
 * 
 * @return One if finished, zero if still running. */
int RunningWorkProcess::weAreFinishedYet()
{
   apr_status_t status;
   int result;
   apr_exit_why_e why;
   if (!finished)
   {
      status = apr_proc_wait(&tproc, &result, &why, APR_NOWAIT);
      finished |= (APR_STATUS_IS_CHILD_DONE(status));
   }
   return finished;
}
